<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta name="categories" content="JavaEE,Spring,SpringMVC">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>RedirectAttribute的用法及原理</title>
</head>
<body>
	<div class="article-wrapper">
		<article>
			<h1 class="title">RedirectAttribute的用法及原理</h1>
			<hr />
			<section>
				<p>重定向和转发是Web应用中常用的两种请求方式，这两种方式有着本质的区别。SpringMVC对两者提供了很好的支持，这篇文章介绍的就是SpringMVC对重定向的支持。首先，介绍一下重定向和转发的区别。</p>
				<p>一句话概括二者的区别：<span class="red-font">“转发是服务器行为，重定向是客户端行为”</span>。</p>
				<br>
				<div class="border-01 annotation">
					<p><span class="bold-font">重定向：</span>重定向在浏览器一端可以看到明显的URL跳转，实际上就是重新请求了另一个URL。重定向过程中，Request域的属性都将丢失，因为HTTP协议是无状态的协议，并且这已经是第二次HTTP请求了。</p>
					<p><span class="bold-font">转发：</span>“一次请求，一次响应”，地址栏的URL不会改变。转发是在服务器端执行，所以转发只能在同一台服务器上进行。它的特点是，速度快，并且Request域的属性不会丢失掉。</p>
				</div>
			</section>
			<section>
				<p>由此可见，重定向最大的弊端是，会丢失Request域中的属性。因此，SpringMVC采用RedirectAttribute来解决了这一问题。下面介绍一下SpirngMVC中重定向的所有方式，这其中包括RedirectAttribute。</p>
				<p>在SpringMVC的InternalResourceViewResolver支持带“命令”的逻辑视图名，所谓的命令就是“redirect:xxx”和“forward:xxx”，意思就是重定向或者跳转到指定的逻辑视图。</p>
				<p>以下所有写法都可以实现请求的重定向：</p>
				<code>
				@RequestMapping("/")<br />
				public String function(Model model) {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;model.addAttribute("test", 123);<br />
				&nbsp;&nbsp;&nbsp;&nbsp;return "redirect:/index";<br />
				}
				</code>
				<code>
				@RequestMapping("/")<br />
				public String function(RedirectAttribute attribute) {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;attribute.addAttribute("test", 123);<br />
				&nbsp;&nbsp;&nbsp;&nbsp;return "redirect:/index";<br />
				}
				</code>
				<code>
				@RequestMapping("/")<br />
				public String function(RedirectAttribute attribute) {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;attribute.addFlashAttribute("test", 123);<br />
				&nbsp;&nbsp;&nbsp;&nbsp;return "redirect:/index";<br />
				}
				</code>
				<p>
				前两者和后者有着明显的区别：经过实验发现，前两种方式会将设置的Attribute全不加到URL的请求参数上去，而最后一种方式却不在URL中加任何参数。
				原因是，最后一种写法将Attribute放到了Session中去，在重定向的请求完毕后立刻删掉Session中的Attribute。
				</p>
				<p class="red-font">
				值得注意的是，SpringMVC对Session的处理是透明的，并不是简单的将上一次请求所设置的Attribute放到Session和Request中，而是做了简单的封装。
				但是，却可以从重定向的JSP页面中获取到这个值。原因是，SpringMVC将这些Attribute放到了Model中，Controller执行完毕后，将Model中所有Attribute设置到Request中。
				</p>
				<p>不过，SpringMVC依然提供了工具类，来访问Request域中封装的Attribute。下面两段代码就是访问这些Attribute的两种方式，不过一般不采用第二种方式。</p>
				<code>
				@RequestMapping("/index")<br />
				public String function(Model model) {<br />
				&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(model.getAttribute("test"));<br />
				&nbsp;&nbsp;&nbsp;&nbsp;return "redirect:/index";<br />
				}
				</code>
				<code>
				Map&lt;String, Object&gt; attribute = RequestContextUtils.getFlashMapManager(request);
				</code>
			</section>
		</article>
	</div>
</body>
</html>